<template>
  <div class="upload-image">
    <div :class="['picture-list', { len1: limit === 1 }]">
      <div class="picture-item" v-for="(item, index) in fileList" :key="item.uid">
        <div class="actions">
          <el-icon class="preview" @click="onPreview(index)">
            <View />
          </el-icon>
          <el-icon class="delete" @click="onDelete(index, item)">
            <Delete />
          </el-icon>
        </div>

        <el-image
          class="file-img"
          ref="fileImageRef"
          :src="item.url"
          :preview-src-list="fileList.map(el => el.url)"
          :initial-index="index"
          fit="cover"
        />
      </div>
    </div>

    <el-upload
      :class="['upload-wrap', { hide: hideUpload }]"
      ref="elUploadRef"
      drag
      accept="image/*"
      :action="action"
      :data="{ route: UPLOAD_DIR() }"
      :file-list="fileList"
      :show-file-list="false"
      :limit="limit"
      :on-progress="onProgress"
      :on-success="onSuccess"
      :on-error="onError"
      :on-remove="onRemove"
      :disabled="disabled || isLoading"
      :before-upload="beforeUpload"
    >
      <el-icon>
        <Plus />
      </el-icon>
    </el-upload>
  </div>
</template>

<script>
import { ref, reactive, computed, watch } from 'vue'
import { uploadUrl } from '@/api/upload'
import { UPLOAD_DIR } from '@/config/oss'

export default {
  name: 'UpdateImage',
  props: {
    // 上传文件列表
    modelValue: Array,

    // 上传数量限制
    limit: {
      type: Number,
      default: 1
    },

    // 上传接口地址
    action: {
      type: String,
      default: uploadUrl
    },

    // 上传前的回调
    beforeUpload: Function,

    // 是否禁用
    disabled: Boolean
  },
  emits: ['input', 'change', 'update:model-value'],
  setup (props, { emit }) {
    const elUploadRef = ref(null)
    const fileImageRef = ref(null)
    const fileList = reactive([])
    const isLoading = ref(false) // 是否上传中

    // 是否隐藏上传区域
    const hideUpload = computed(() => {
      if (props.limit === 0 || fileList.length >= props.limit) return true

      return false
    })

    watch(
      () => props.modelValue,
      (modelValue) => {
        if (!modelValue || !modelValue.length) {
          fileList.length = 0
          return false
        }

        modelValue.forEach((el, i) => {
          const file = {
            status: 'success',
            uid: Date.now() + i,
            url: el
          }
          fileList[i] = file
        })
      },
      { deep: true, immediate: true }
    )

    // 上传文件中回调
    const onProgress = () => {
      isLoading.value = true
    }

    // 上传文件成功回调
    const onSuccess = (res, file) => {
      const { code, data: { url } } = res
      const { uid } = file

      if (code === 200) {
        const index = fileList.findIndex((el) => el.uid === uid)

        if (index > -1) {
          fileList[index].url = url
        } else {
          const current = { status: 'success', uid, url }
          fileList.push(current)
        }

        emitChange(fileList)
      }

      isLoading.value = false
    }

    // 上传文件失败回调
    const onError = () => {
      isLoading.value = false
    }

    // 移除文件回调
    const onRemove = (_, files) => {
      fileList.length = 0
      files.forEach(file => fileList.push(file))
      emitChange(fileList)
    }

    // 手动移除文件
    const onDelete = async (_, item) => {
      await elUploadRef.value.handleRemove(item)
      // fileList.splice(i, 1)
      // emitChange(fileList)
    }

    // 预览图片
    const onPreview = (i) => {
      const previewImage = fileImageRef.value[i].$el.querySelector('.el-image__preview')
      previewImage.click()
    }

    // 文件列表数据改变事件分发
    const emitChange = (value) => {
      const urls = value.map(el => el.url)

      emit('change', urls)
      emit('input', urls)
      emit('update:model-value', urls)
    }

    return {
      UPLOAD_DIR,
      fileImageRef,
      elUploadRef,
      isLoading,
      fileList,
      hideUpload,

      onProgress,
      onSuccess,
      onError,
      onRemove,
      onDelete,
      onPreview
    }
  }
}
</script>

<style lang="scss" scoped>
.upload-image {
  line-height: 0;

  .picture-list {
    display: inline-block;

    &.len1 .picture-item {
      margin-bottom: 0;
    }

    .picture-item {
      width: 96px;
      height: 96px;
      box-sizing: border-box;
      display: inline-block;
      position: relative;
      margin-bottom: 8px;
      border-radius: 6px;
      overflow: hidden;
      cursor: pointer;
      .actions {
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        right: 0;
        z-index: 2;
        display: flex;
        align-items: center;
        justify-content: center;
        background-color: rgba(0, 0, 0, 0.5);
        opacity: 0;
        transition: opacity 0.3s;
        color: #fff;
        &:hover {
          opacity: 1;
          background-color: rgba(0, 0, 0, 0.5);
        }
        .el-icon {
          font-size: 20px;
          & + .el-icon {
            margin-left: 5px;
          }
        }
      }

      .file-img {
        width: 100%;
        height: 100%;
      }
    }
    .picture-item + .picture-item {
      margin-right: 8px;
    }
  }

  .upload-wrap {
    display: inline-block;
    ::v-deep(.el-upload) {
      width: 96px;
      height: 96px;
      position: relative;
      border: none;
      .el-upload-dragger {
        position: absolute;
        width: 100%;
        height: 100%;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        .el-icon-upload {
          margin: 0;
          font-size: 40px;
        }
      }
    }
  }

  .hide {
    display: none;
  }
}
</style>
